package com.jinkeen.xiaxie.customView;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Region;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

import com.jinkeen.xiaxie.R;

public class StickView extends View {

    private OnDirectionListener onDirectionListener;

    public enum Direction {
        UP, LEFT, DOWN, RIGHT
    }

    public interface OnDirectionListener {
        void onDirection(Direction direction);
    }

    public void setOnDirectionListener(OnDirectionListener onDirectionListener) {
        this.onDirectionListener = onDirectionListener;
    }

    private int width, height;

    private final static String TAG = "StickView";

    private int edgeRadius;

    private int stickRadius;

    private Region stickRegion = new Region();
    private Region edgeRegion = new Region();

    private int stickX, stickY;

    private Point centerPoint = new Point();

    private Paint paint = new Paint();

    public StickView(Context context) {
        super(context);
    }

    public StickView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public StickView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawEdge(canvas);
        drawStick(canvas);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
        centerPoint.x = w / 2;
        centerPoint.y = h / 2;
        stickRadius =  (w > h ? h : w) / 8;
        edgeRadius = (w > h ? h : w) * 2 / 5;
        resetStick();
        initialRegion();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        int x = (int)event.getX();
        int y = (int)event.getY();

        int action = event.getAction();

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                if (stickRegion.contains(x, y)) {
                    return true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (edgeRegion.contains(x, y)) {
                    updateStick(x, y);
                } else {
                    resetStick();
                }
                break;
            case MotionEvent.ACTION_UP:
                resetStick();
                break;
        }

        return super.onTouchEvent(event);
    }

    private void drawEdge(Canvas canvas) {

        paint.reset();
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(getResources().getColor(R.color.white_01, null));
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);
        canvas.drawCircle(centerPoint.x, centerPoint.y, edgeRadius, paint);

    }

    private void drawStick(Canvas canvas) {

        paint.reset();
        paint.setColor(getResources().getColor(R.color.white, null));
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);
        canvas.drawCircle(stickX, stickY, stickRadius, paint);

    }

    private void resetStick() {

        stickX = width / 2;
        stickY = height / 2;
        invalidate();

    }

    private void initialRegion() {

        Path stickPath = new Path();
        stickPath.addCircle(centerPoint.x, centerPoint.y, stickRadius, Path.Direction.CW);
        Region globalRegion = new Region(centerPoint.x - stickRadius, centerPoint.y - stickRadius, centerPoint.x + stickRadius, centerPoint.y + stickRadius);
        stickRegion.setPath(stickPath, globalRegion);

        Path edgePath = new Path();
        edgePath.addCircle(centerPoint.x, centerPoint.y, edgeRadius * 2, Path.Direction.CW);
        globalRegion = new Region(centerPoint.x - edgeRadius * 2, centerPoint.y - edgeRadius * 2, centerPoint.x + edgeRadius * 2, centerPoint.y + edgeRadius * 2);
        edgeRegion.setPath(edgePath, globalRegion);

    }

    private void updateStick(int x, int y) {

        int dx = x - centerPoint.x;
        int dy = y - centerPoint.y;

        stickX = x - dx / 4;
        stickY = y - dy / 4;

        double degree = calculateAngle(dx, dy);
        invalidate();

        if (onDirectionListener != null) {
            if (degree > 0 && degree < 45 || degree > 325 && degree < 360) {
                onDirectionListener.onDirection(Direction.RIGHT);
            } else if (degree > 45 && degree < 135){
                onDirectionListener.onDirection(Direction.DOWN);
            } else if (degree > 135 && degree < 225) {
                onDirectionListener.onDirection(Direction.LEFT);
            } else if (degree > 225 && degree < 325){
                onDirectionListener.onDirection(Direction.UP);
            }
        }

        Log.d(TAG, "" + degree);

    }

    private double calculateAngle(float dx, float dy) {
        double degrees = Math.toDegrees(Math.atan2(dy, dx));
        return degrees < 0 ? Math.floor(degrees + 360) : Math.floor(degrees);
    }

}
